package org.example.erat.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.erat.dto.ExperimentDTO;
import org.example.erat.dto.ReportDTO;
import org.example.erat.dto.StatisticsDTO;
import org.example.erat.dto.StudentDTO;
import org.example.erat.entity.*;
import org.example.erat.exception.ResourceNotFoundException;
import org.example.erat.log.core.LoggerSingleton;
import org.example.erat.repository.*;
import org.example.erat.service.ReportAnalysisService;
import org.example.erat.service.ReportService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 实验报告服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ReportServiceImpl implements ReportService {

    private final ReportRepository reportRepository;
    private final StudentRepository studentRepository;
    private final ExperimentRepository experimentRepository;
    private final ClassRepository classRepository;
    private final CourseRepository courseRepository;
    private final ReportAnalysisService reportAnalysisService;

    @Value("${file.upload-dir}")
    private String uploadDir;

    @Override
    @Transactional
    public ReportDTO uploadReport(Long studentId, Long experimentId, MultipartFile file) {
        log.info("上传实验报告: 学生ID={}, 实验ID={}, 文件名={}", studentId, experimentId, file.getOriginalFilename());

        Student student = studentRepository.findById(studentId)
                .orElseThrow(() -> new ResourceNotFoundException("学生不存在: " + studentId));

        Experiment experiment = experimentRepository.findById(experimentId)
                .orElseThrow(() -> new ResourceNotFoundException("实验不存在: " + experimentId));

        // 检查学生是否已提交该实验报告
        reportRepository.findByStudentAndExperiment(student, experiment)
                .ifPresent(r -> {
                    throw new IllegalArgumentException("该学生已提交此实验报告");
                });

        try {
            // 创建上传目录
            String courseDir = experiment.getCourse().getName();
            String classDir = student.getClassEntity().getName();
            String experimentDir = experiment.getName();

            Path uploadPath = Paths.get(uploadDir, courseDir, classDir, experimentDir);
            Files.createDirectories(uploadPath);

            // 构建文件名: 实验名_学号_姓名.扩展名
            String originalFilename = file.getOriginalFilename();
            String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
            String newFilename = experiment.getName() + "_" + student.getStudentId() + "_" + student.getName() + extension;

            Path filePath = uploadPath.resolve(newFilename);
            Files.copy(file.getInputStream(), filePath);

            // 保存报告记录
            Report report = Report.builder()
                    .fileName(newFilename)
                    .filePath(filePath.toString())
                    .submissionTime(LocalDateTime.now())
                    .student(student)
                    .experiment(experiment)
                    .build();

            Report savedReport = reportRepository.save(report);
            return convertToDTO(savedReport);

        } catch (IOException e) {
            log.error("上传实验报告失败", e);
            throw new RuntimeException("上传实验报告失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public void deleteReport(Long id) {
        log.info("删除实验报告: {}", id);

        Report report = reportRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("实验报告不存在: " + id));

        // 删除文件
        try {
            Files.deleteIfExists(Paths.get(report.getFilePath()));
        } catch (IOException e) {
            log.error("删除实验报告文件失败", e);
        }

        reportRepository.delete(report);
    }

    @Override
    public ReportDTO getReport(Long id) {
        log.info("获取实验报告: {}", id);

        Report report = reportRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("实验报告不存在: " + id));

        return convertToDTO(report);
    }

    @Override
    public List<ReportDTO> getReportsByStudent(Long studentId) {
        log.info("获取学生的实验报告列表: {}", studentId);

        Student student = studentRepository.findById(studentId)
                .orElseThrow(() -> new ResourceNotFoundException("学生不存在: " + studentId));

        List<Report> reports = reportRepository.findByStudent(student);
        return reports.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<ReportDTO> getReportsByExperiment(Long experimentId) {
        log.info("获取实验的实验报告列表: {}", experimentId);

        Experiment experiment = experimentRepository.findById(experimentId)
                .orElseThrow(() -> new ResourceNotFoundException("实验不存在: " + experimentId));

        List<Report> reports = reportRepository.findByExperiment(experiment);
        return reports.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public boolean scanAndAnalyzeReports(Long classId, Long courseId, String directoryPath) {
        log.info("扫描并分析实验报告: 班级ID={}, 课程ID={}, 目录={}", classId, courseId, directoryPath);

        try {
            // 使用 ReportAnalysisService 分析报告目录
            Map<String, Object> analysisResult = reportAnalysisService.analyzeReports(classId, courseId, directoryPath);

            // 检查分析结果
            if (analysisResult == null || analysisResult.isEmpty()) {
                log.warn("分析结果为空");
                return false;
            }

            // 获取班级和课程信息
            ClassEntity classEntity = classRepository.findById(classId)
                    .orElseThrow(() -> new ResourceNotFoundException("班级不存在: " + classId));

            Course course = courseRepository.findById(courseId)
                    .orElseThrow(() -> new ResourceNotFoundException("课程不存在: " + courseId));

            // 获取班级学生列表
            List<Student> students = studentRepository.findByClassEntity(classEntity);
            if (students.isEmpty()) {
                log.warn("班级没有学生: {}", classId);
                return false;
            }

            // 清除该班级和课程的旧报告记录，确保统计结果反映最新的扫描结果
            try {
                List<Report> oldReports = reportRepository.findByStudentClassEntityAndExperimentCourse(classEntity, course);
                if (!oldReports.isEmpty()) {
                    log.info("清除旧的报告记录: {} 条", oldReports.size());
                    LoggerSingleton.getInstance().info("清除旧的报告记录: {} 条", oldReports.size());

                    // 打印要删除的记录，便于调试
                    for (Report report : oldReports) {
                        LoggerSingleton.getInstance().info("  - 删除报告: 学生={}, 实验={}, 文件={}",
                                report.getStudent().getName(),
                                report.getExperiment().getName(),
                                report.getFileName());
                    }

                    reportRepository.deleteAll(oldReports);
                    reportRepository.flush(); // 确保删除操作立即执行

                    // 验证删除是否成功
                    List<Report> remainingReports = reportRepository.findByStudentClassEntityAndExperimentCourse(classEntity, course);
                    if (remainingReports.isEmpty()) {
                        LoggerSingleton.getInstance().info("成功清除所有旧报告记录");
                    } else {
                        LoggerSingleton.getInstance().warn("清除旧报告记录后仍有 {} 条记录", remainingReports.size());
                    }
                } else {
                    LoggerSingleton.getInstance().info("没有找到需要清除的旧报告记录");
                }
            } catch (Exception e) {
                log.error("清除旧报告记录失败", e);
                LoggerSingleton.getInstance().error("清除旧报告记录失败: {}", e.getMessage());
            }

            // 获取课程实验列表
            List<Experiment> experiments = experimentRepository.findByCourse(course);
            if (experiments.isEmpty()) {
                log.warn("课程没有实验: {}", courseId);
                return false;
            }

            // 扫描目录
            File rootDirectory = new File(directoryPath);
            if (!rootDirectory.exists() || !rootDirectory.isDirectory()) {
                log.error("目录不存在或不是目录: {}", directoryPath);
                LoggerSingleton.getInstance().error("目录不存在或不是目录: {}", directoryPath);
                return false;
            }

            // 打印目录内容，便于调试
            File[] rootFiles = rootDirectory.listFiles();
            if (rootFiles == null || rootFiles.length == 0) {
                String warnMsg = "目录为空: " + directoryPath;
                log.warn(warnMsg);
                LoggerSingleton.getInstance().warn(warnMsg);
                return false;
            } else {
                LoggerSingleton.getInstance().info("目录 {} 包含 {} 个文件/子目录", directoryPath, rootFiles.length);
                for (File file : rootFiles) {
                    LoggerSingleton.getInstance().info("  - {}: {}", file.isDirectory() ? "目录" : "文件", file.getName());
                }
            }

            // 处理计数器
            int processedCount = 0;

            // 查找班级目录
            File classDirectory = findClassDirectory(rootDirectory, classEntity.getName());
            if (classDirectory == null) {
                log.warn("未找到班级目录: {}，使用根目录作为班级目录", classEntity.getName());
                classDirectory = rootDirectory;
            }

            // 遍历实验目录
            for (Experiment experiment : experiments) {
                File experimentDirectory = findExperimentDirectory(classDirectory, experiment.getName());
                if (experimentDirectory == null) {
                    log.warn("未找到实验目录: {}", experiment.getName());
                    continue;
                }

                // 扫描实验目录中的报告文件
                File[] reportFiles = experimentDirectory.listFiles(File::isFile);
                if (reportFiles == null || reportFiles.length == 0) {
                    log.warn("实验目录为空: {}", experimentDirectory.getAbsolutePath());
                    continue;
                }

                // 处理每个报告文件
                for (File reportFile : reportFiles) {
                    String fileName = reportFile.getName();

                    // 解析文件名: 实验名_学号_姓名.扩展名
                    int lastDotIndex = fileName.lastIndexOf(".");
                    if (lastDotIndex == -1) {
                        log.warn("文件名格式不正确 (无扩展名): {}", fileName);
                        continue;
                    }

                    String[] parts = fileName.substring(0, lastDotIndex).split("_");
                    if (parts.length < 3) {
                        log.warn("文件名格式不正确 (格式应为: 实验名_学号_姓名.扩展名): {}", fileName);
                        continue;
                    }

                    String experimentName = parts[0];
                    String studentId = parts[1];
                    String studentName = parts[2];

                    // 检查实验名是否匹配
                    if (!experiment.getName().equals(experimentName)) {
                        log.warn("文件名中的实验名 {} 与目录名 {} 不匹配", experimentName, experiment.getName());
                        continue;
                    }

                    // 查找学生
                    Student student = students.stream()
                            .filter(s -> s.getStudentId().equals(studentId))
                            .findFirst()
                            .orElse(null);

                    if (student == null) {
                        log.warn("未找到学生: {}", studentId);
                        continue;
                    }

                    // 检查学生姓名是否匹配
                    if (!student.getName().equals(studentName)) {
                        log.warn("学生姓名不匹配: 文件中={}, 数据库中={}", studentName, student.getName());
                        continue;
                    }

                    // 检查是否已存在报告记录
                    if (reportRepository.findByStudentAndExperiment(student, experiment).isPresent()) {
                        log.info("报告已存在: 学生={}, 实验={}", student.getName(), experiment.getName());
                        continue;
                    }

                    // 保存报告记录
                    try {
                        // 创建上传目录
                        String courseDir = course.getName();
                        String classDir = classEntity.getName();
                        String experimentDir = experiment.getName();

                        // 记录目录信息，便于调试
                        LoggerSingleton.getInstance().info("创建上传目录: 课程={}, 班级={}, 实验={}",
                                courseDir, classDir, experimentDir);

                        Path targetPath = null;
                        try {
                            Path uploadPath = Paths.get(uploadDir, courseDir, classDir, experimentDir);
                            LoggerSingleton.getInstance().info("上传路径: {}", uploadPath.toAbsolutePath());

                            // 确保目录存在
                            Files.createDirectories(uploadPath);

                            // 检查目录是否创建成功
                            if (!Files.exists(uploadPath)) {
                                throw new IOException("无法创建目录: " + uploadPath.toAbsolutePath());
                            }

                            targetPath = uploadPath.resolve(fileName);
                            LoggerSingleton.getInstance().info("目标文件路径: {}", targetPath.toAbsolutePath());

                            // 复制文件
                            Files.copy(reportFile.toPath(), targetPath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);

                            // 检查文件是否复制成功
                            if (!Files.exists(targetPath)) {
                                throw new IOException("文件复制失败: " + targetPath.toAbsolutePath());
                            }

                            LoggerSingleton.getInstance().info("文件复制成功: {}", targetPath.toAbsolutePath());
                        } catch (IOException e) {
                            LoggerSingleton.getInstance().error("创建目录或复制文件失败: {}", e.getMessage());
                            throw e;
                        }

                        // 如果文件复制成功，创建报告记录
                        if (targetPath != null) {
                            Report report = Report.builder()
                                    .fileName(fileName)
                                    .filePath(targetPath.toString())
                                    .submissionTime(LocalDateTime.now())
                                    .student(student)
                                    .experiment(experiment)
                                    .build();

                            try {
                                Report savedReport = reportRepository.save(report);
                                if (savedReport != null && savedReport.getId() != null) {
                                    processedCount++;
                                    log.info("成功保存报告记录到数据库: {}", fileName);
                                    LoggerSingleton.getInstance().info("成功处理学生 {} 的实验 {} 报告: {}",
                                        student.getName(), experiment.getName(), fileName);
                                } else {
                                    log.error("保存报告记录失败: {}", fileName);
                                    LoggerSingleton.getInstance().error("保存报告记录失败: {}", fileName);
                                }
                            } catch (Exception e) {
                                log.error("保存报告记录异常: {}, 错误: {}", fileName, e.getMessage());
                                LoggerSingleton.getInstance().error("保存报告记录异常: {}, 错误: {}", fileName, e.getMessage());
                            }
                        }

                    } catch (IOException e) {
                        log.error("处理文件失败: {}", fileName, e);
                        LoggerSingleton.getInstance().error("处理文件失败: {}, 错误: {}", fileName, e.getMessage());
                    }
                }
            }

            log.info("成功处理 {} 个实验报告文件", processedCount);
            LoggerSingleton.getInstance().info("成功处理 {} 个实验报告文件", processedCount);

            // 返回处理结果
            return processedCount > 0;

        } catch (Exception e) {
            log.error("扫描并分析实验报告失败", e);
            LoggerSingleton.getInstance().error("扫描并分析实验报告失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 查找班级目录
     * @param rootDir 根目录
     * @param className 班级名称
     * @return 班级目录
     */
    private File findClassDirectory(File rootDir, String className) {
        File[] files = rootDir.listFiles(File::isDirectory);
        if (files == null) return null;

        // 首先尝试精确匹配
        for (File file : files) {
            if (file.getName().equals(className)) {
                return file;
            }
        }

        // 然后尝试包含匹配
        for (File file : files) {
            if (file.getName().contains(className)) {
                return file;
            }
        }

        return null;
    }

    /**
     * 查找实验目录
     * @param classDir 班级目录
     * @param experimentName 实验名称
     * @return 实验目录
     */
    private File findExperimentDirectory(File classDir, String experimentName) {
        File[] files = classDir.listFiles(File::isDirectory);
        if (files == null) return null;

        // 首先尝试精确匹配
        for (File file : files) {
            if (file.getName().equals(experimentName)) {
                return file;
            }
        }

        // 然后尝试包含匹配
        for (File file : files) {
            if (file.getName().contains(experimentName)) {
                return file;
            }
        }

        return null;
    }

    @Override
    public List<StatisticsDTO.ExperimentStatistics> getExperimentStatistics(Long classId, Long courseId) {
        log.info("获取实验维度统计: 班级ID={}, 课程ID={}", classId, courseId);
        LoggerSingleton.getInstance().info("获取实验维度统计: 班级ID={}, 课程ID={}", classId, courseId);

        ClassEntity classEntity = classRepository.findById(classId)
                .orElseThrow(() -> new ResourceNotFoundException("班级不存在: " + classId));

        Course course = courseRepository.findById(courseId)
                .orElseThrow(() -> new ResourceNotFoundException("课程不存在: " + courseId));

        // 获取班级学生列表
        List<Student> students = studentRepository.findByClassEntity(classEntity);
        if (students.isEmpty()) {
            LoggerSingleton.getInstance().warn("班级 {} 没有学生", classEntity.getName());
            return new ArrayList<>();
        }

        // 获取课程实验列表
        List<Experiment> experiments = experimentRepository.findByCourse(course);
        if (experiments.isEmpty()) {
            LoggerSingleton.getInstance().warn("课程 {} 没有实验", course.getName());
            return new ArrayList<>();
        }

        // 获取该班级和课程的所有报告
        List<Report> allReports = reportRepository.findByStudentClassEntityAndExperimentCourse(classEntity, course);
        LoggerSingleton.getInstance().info("找到 {} 个报告记录", allReports.size());

        // 打印报告记录详情，便于调试
        for (Report report : allReports) {
            LoggerSingleton.getInstance().info("报告记录: 学生={}({}), 实验={}, 文件={}",
                    report.getStudent().getName(),
                    report.getStudent().getStudentId(),
                    report.getExperiment().getName(),
                    report.getFileName());
        }

        // 计算每个实验的统计数据
        return experiments.stream()
                .map(experiment -> {
                    // 获取已提交报告的学生
                    List<Report> reports = allReports.stream()
                            .filter(r -> r.getExperiment().getId().equals(experiment.getId()))
                            .collect(Collectors.toList());

                    LoggerSingleton.getInstance().info("实验 {}: 找到 {} 个报告记录",
                            experiment.getName(), reports.size());

                    // 打印该实验的报告记录
                    for (Report report : reports) {
                        LoggerSingleton.getInstance().info("  - 报告: 学生={}({}), 文件={}",
                                report.getStudent().getName(),
                                report.getStudent().getStudentId(),
                                report.getFileName());
                    }

                    List<Student> submittedStudents = reports.stream()
                            .map(Report::getStudent)
                            .distinct() // 确保不重复计算同一个学生
                            .collect(Collectors.toList());

                    LoggerSingleton.getInstance().info("实验 {}: 已提交学生数={}",
                            experiment.getName(), submittedStudents.size());

                    // 打印已提交学生名单
                    for (Student student : submittedStudents) {
                        LoggerSingleton.getInstance().info("  - 已提交学生: {}({})",
                                student.getName(), student.getStudentId());
                    }

                    // 计算缺交学生
                    List<Student> missingStudents = students.stream()
                            .filter(student -> submittedStudents.stream()
                                    .noneMatch(s -> s.getId().equals(student.getId())))
                            .collect(Collectors.toList());

                    LoggerSingleton.getInstance().info("实验 {}: 缺交学生数={}",
                            experiment.getName(), missingStudents.size());

                    // 打印缺交学生名单
                    for (Student student : missingStudents) {
                        LoggerSingleton.getInstance().info("  - 缺交学生: {}({})",
                                student.getName(), student.getStudentId());
                    }

                    // 转换为DTO
                    List<StudentDTO> missingStudentDTOs = missingStudents.stream()
                            .map(student -> StudentDTO.builder()
                                    .id(student.getId())
                                    .studentId(student.getStudentId())
                                    .name(student.getName())
                                    .grade(student.getGrade())
                                    .major(student.getMajor())
                                    .build())
                            .collect(Collectors.toList());

                    int totalStudents = students.size();
                    int submittedCount = submittedStudents.size();
                    int missingCount = missingStudents.size();
                    double submissionRate = totalStudents > 0 ? (double) submittedCount / totalStudents : 0;

                    return StatisticsDTO.ExperimentStatistics.builder()
                            .experimentId(experiment.getId())
                            .experimentName(experiment.getName())
                            .totalStudents(totalStudents)
                            .submittedCount(submittedCount)
                            .missingCount(missingCount)
                            .submissionRate(submissionRate)
                            .missingStudents(missingStudentDTOs)
                            .build();
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<StatisticsDTO.StudentStatistics> getStudentStatistics(Long classId, Long courseId) {
        log.info("获取学生维度统计: 班级ID={}, 课程ID={}", classId, courseId);
        LoggerSingleton.getInstance().info("获取学生维度统计: 班级ID={}, 课程ID={}", classId, courseId);

        ClassEntity classEntity = classRepository.findById(classId)
                .orElseThrow(() -> new ResourceNotFoundException("班级不存在: " + classId));

        Course course = courseRepository.findById(courseId)
                .orElseThrow(() -> new ResourceNotFoundException("课程不存在: " + courseId));

        // 获取班级学生列表
        List<Student> students = studentRepository.findByClassEntity(classEntity);
        if (students.isEmpty()) {
            LoggerSingleton.getInstance().warn("班级 {} 没有学生", classEntity.getName());
            return new ArrayList<>();
        }

        // 获取课程实验列表
        List<Experiment> experiments = experimentRepository.findByCourse(course);
        if (experiments.isEmpty()) {
            LoggerSingleton.getInstance().warn("课程 {} 没有实验", course.getName());
            return new ArrayList<>();
        }

        // 获取该班级和课程的所有报告
        List<Report> allReports = reportRepository.findByStudentClassEntityAndExperimentCourse(classEntity, course);
        LoggerSingleton.getInstance().info("找到 {} 个报告记录", allReports.size());

        // 打印报告记录详情，便于调试
        for (Report report : allReports) {
            LoggerSingleton.getInstance().info("报告记录: 学生={}({}), 实验={}, 文件={}",
                    report.getStudent().getName(),
                    report.getStudent().getStudentId(),
                    report.getExperiment().getName(),
                    report.getFileName());
        }

        // 计算每个学生的统计数据
        return students.stream()
                .map(student -> {
                    // 获取学生已提交的实验
                    List<Report> studentReports = allReports.stream()
                            .filter(r -> r.getStudent().getId().equals(student.getId()))
                            .collect(Collectors.toList());

                    LoggerSingleton.getInstance().info("学生 {}({}): 找到 {} 个报告记录",
                            student.getName(), student.getStudentId(), studentReports.size());

                    // 打印该学生的报告记录
                    for (Report report : studentReports) {
                        LoggerSingleton.getInstance().info("  - 报告: 实验={}, 文件={}",
                                report.getExperiment().getName(),
                                report.getFileName());
                    }

                    List<Experiment> submittedExperiments = studentReports.stream()
                            .map(Report::getExperiment)
                            .distinct() // 确保不重复计算同一个实验
                            .collect(Collectors.toList());

                    LoggerSingleton.getInstance().info("学生 {}({}): 已提交实验数={}",
                            student.getName(), student.getStudentId(), submittedExperiments.size());

                    // 打印已提交实验列表
                    for (Experiment experiment : submittedExperiments) {
                        LoggerSingleton.getInstance().info("  - 已提交实验: {}",
                                experiment.getName());
                    }

                    // 计算缺交实验
                    List<Experiment> missingExperiments = experiments.stream()
                            .filter(experiment -> submittedExperiments.stream()
                                    .noneMatch(e -> e.getId().equals(experiment.getId())))
                            .collect(Collectors.toList());

                    LoggerSingleton.getInstance().info("学生 {}({}): 缺交实验数={}",
                            student.getName(), student.getStudentId(), missingExperiments.size());

                    // 打印缺交实验列表
                    for (Experiment experiment : missingExperiments) {
                        LoggerSingleton.getInstance().info("  - 缺交实验: {}",
                                experiment.getName());
                    }

                    // 转换为DTO
                    List<ExperimentDTO> missingExperimentDTOs = missingExperiments.stream()
                            .map(experiment -> ExperimentDTO.builder()
                                    .id(experiment.getId())
                                    .name(experiment.getName())
                                    .experimentNumber(experiment.getExperimentNumber())
                                    .build())
                            .collect(Collectors.toList());

                    int totalExperiments = experiments.size();
                    int submittedCount = submittedExperiments.size();
                    int missingCount = missingExperiments.size();
                    double submissionRate = totalExperiments > 0 ? (double) submittedCount / totalExperiments : 0;

                    return StatisticsDTO.StudentStatistics.builder()
                            .studentId(student.getId())
                            .studentName(student.getName())
                            .totalExperiments(totalExperiments)
                            .submittedCount(submittedCount)
                            .missingCount(missingCount)
                            .submissionRate(submissionRate)
                            .missingExperiments(missingExperimentDTOs)
                            .build();
                })
                .collect(Collectors.toList());
    }

    @Override
    public StatisticsDTO.VisualizationData getVisualizationData(Long classId, Long courseId) {
        log.info("获取可视化统计数据: 班级ID={}, 课程ID={}", classId, courseId);

        // 获取实验维度统计
        List<StatisticsDTO.ExperimentStatistics> experimentStatistics = getExperimentStatistics(classId, courseId);

        // 提取实验名称和提交率
        List<String> experimentNames = experimentStatistics.stream()
                .map(StatisticsDTO.ExperimentStatistics::getExperimentName)
                .collect(Collectors.toList());

        List<Double> submissionRates = experimentStatistics.stream()
                .map(stats -> stats.getSubmissionRate() * 100) // 转换为百分比
                .collect(Collectors.toList());

        return StatisticsDTO.VisualizationData.builder()
                .experimentNames(experimentNames)
                .submissionRates(submissionRates)
                .build();
    }

    /**
     * 将实验报告实体转换为DTO
     * @param report 实验报告实体
     * @return 实验报告DTO
     */
    private ReportDTO convertToDTO(Report report) {
        return ReportDTO.builder()
                .id(report.getId())
                .fileName(report.getFileName())
                .filePath(report.getFilePath())
                .submissionTime(report.getSubmissionTime())
                .studentId(report.getStudent().getId())
                .studentName(report.getStudent().getName())
                .experimentId(report.getExperiment().getId())
                .experimentName(report.getExperiment().getName())
                .build();
    }
}
